package edu.ccut.saturn.studio.database.ui;

import java.io.File;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Collection;

import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.IMessageProvider;
import org.eclipse.jface.dialogs.TitleAreaDialog;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;


import edu.ccut.saturn.studio.Activator;
import edu.ccut.saturn.studio.Images;
import edu.ccut.saturn.studio.core.util.eclipse.Messages;
import edu.ccut.saturn.studio.core.util.eclipse.SaturnDialogSettings;
import edu.ccut.saturn.studio.core.util.eclipse.SaturnDialogUtil;
import edu.ccut.saturn.studio.core.util.eclipse.SaturnValidation;
import edu.ccut.saturn.studio.database.model.DBConnection;
import edu.ccut.saturn.studio.database.model.DBConnectionProvider;
import edu.ccut.saturn.studio.database.model.DBConnection.DBConnectionListener;

/**
 * 创建连接向导
 * 
 * @author 谷钰
 * @version 1.0 2008.12.04
 * 
 */
public class ManageConnectionDialog extends TitleAreaDialog {

	public static final String STORE_URL_KEY = "dbURL"; //$NON-NLS-1$
	public static final String STORE_DRIVERPATH_KEY = "driverpath"; //$NON-NLS-1$
	public static final String STORE_SECTION_NAME = "NewDBConnectionDialog"; //$NON-NLS-1$

	private Text nameTxt;
	private Text usridTxt;
	private Text pwdTxt;

	private Button testConBtn;
	private Combo dbTypeCombo;
	private Combo urlCombo;
	private Combo driverPathCombo;
	private Combo driverClassCombo;

	private DBConnection dbConnection;
	private String title;
	private String oldName;

	private boolean canOk;
	private boolean isModify;
	private boolean isInit;

	final private static DriverClassHelpers helper = new DriverClassHelpers();

	public ManageConnectionDialog(Shell shell, DBConnection dbConnections) {
		super(shell);

		if (dbConnections != null) {
			this.dbConnection = dbConnections;
			title = Messages.getString("ManageConnectionDialog.configlink"); //$NON-NLS-1$
			isModify = true;
			oldName = this.dbConnection.getName();
		} else {
			this.dbConnection = new DBConnection(this.getDefaultInitName());
			title = Messages.getString("ManageConnectionDialog.createlink"); //$NON-NLS-1$
		}

		setShellStyle(getShellStyle() | 16);
	}

	protected Point getInitialSize() {
		return new Point(500, 380);
	}

	protected Control createContents(Composite composite) {
		Control control = super.createContents(composite);

		getButton(0).setEnabled(false);

		return control;
	}

	public Control createDialogArea(Composite composite) {
		Composite composite1 = (Composite) super.createDialogArea(composite);
		Composite composite2 = new Composite(composite1, 0);
		initLayout(composite2);
		this.isInit = true;

		createNameField(composite2);
		createDbTypeField(composite2);
		createDriverClassField(composite2);
		createUrlField(composite2);
		createUsrField(composite2);
		createPwdField(composite2);
		createJdbcDriverField(composite2);
		createTestConnectBtnField(composite2);
		refresh();
		
		restoreWidgetValues();

		setTitle(title);
		setMessage(Messages.getString("ManageConnectionDialog.rightconfigparameter")); //$NON-NLS-1$
		setTitleImage(Activator.getImage(Images.DATABASE_NODE9));
		getShell().setText(title);

		this.isInit = false;

		return composite2;
	}

	private void initLayout(Composite composite) {
		GridLayout gridlayout = new GridLayout();
		gridlayout.numColumns = 3;
		gridlayout.marginHeight = 10;
		gridlayout.marginWidth = 10;
		composite.setLayout(gridlayout);
		GridData griddata = new GridData(1808);
		composite.setLayoutData(griddata);
	}

	@Override
	protected void createButtonsForButtonBar(Composite parent) {
		createButton(parent, IDialogConstants.OK_ID, Messages
				.getString("ManageConnectionDialog.confirm"), false); //$NON-NLS-1$
		createButton(parent, IDialogConstants.CANCEL_ID, Messages
				.getString("ManageConnectionDialog.cancel"), false); //$NON-NLS-1$
	}

	private void testConnection() {
		final DBConnection dbconnection = new DBConnection(nameTxt.getText()
				.trim());
		dbconnection.setUsername(usridTxt.getText().trim());
		dbconnection.setPassword(pwdTxt.getText().trim());
		dbconnection.setUrl(urlCombo.getText().trim());
		dbconnection.setDriverPath(driverPathCombo.getText().trim());
		dbconnection.setDriverClassName(driverClassCombo.getText().trim());

		refreshBtnState(false);
		setMessage(Messages.getString("ManageConnectionDialog.databaselinkingtest")); //$NON-NLS-1$

		dbconnection.getConnectionAsync(new DBConnectionListener() {
			public void onGetConnection(Connection connection) {
				final boolean hasConnection = (connection != null);
				
				if (hasConnection) {
					try {
						connection.close();
					} catch (SQLException e) {
						e.printStackTrace();
					}
				}
				
				getShell().getDisplay().asyncExec(new Runnable() {
					public void run() {
						if (hasConnection) {
							setErrorMessage(null);
							setMessage(Messages.getString("ManageConnectionDialog.successfullylinked"), //$NON-NLS-1$
									IMessageProvider.INFORMATION);
						} else {
							setErrorMessage(Messages
									.getString("ManageConnectionDialog.failurelink")); //$NON-NLS-1$
						}
						
						refreshBtnState(hasConnection);
						canOk = hasConnection;
					}
				});
			}
		});
	}

	private void refreshBtnState(boolean isEnable) {
		Button button = getButton(0);
		if (button != null && button.getEnabled() != isEnable) {
			button.setEnabled(isEnable);
		}

		if (testConBtn != null && testConBtn.getEnabled() != isEnable) {
			testConBtn.setEnabled(isEnable);
		}
	}

	private void createTestConnectBtnField(Composite composite) {
		Label label = new Label(composite, 0);
		label.setText(""); //$NON-NLS-1$
		GridData labelData = new GridData();
		labelData.horizontalSpan = 2;
		label.setLayoutData(labelData);
		testConBtn = new Button(composite, 26);
		setButtonLayoutData(testConBtn);
		GridData griddata = (GridData) testConBtn.getLayoutData();
		griddata.horizontalAlignment = 16777224;
		griddata.verticalAlignment = 16777224;
		griddata.horizontalSpan = 3;
		testConBtn.setText(Messages.getString("ManageConnectionDialog.testlink")); //$NON-NLS-1$
		testConBtn.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				testConnection();
			}
		});
	}

	private void createUrlField(Composite composite) {
		Label label = new Label(composite, 0);
		label.setText(Messages.getString("ManageConnectionDialog.linkurl")); //$NON-NLS-1$
		urlCombo = new Combo(composite, 67584);
		urlCombo.setTextLimit(200);
		GridData griddata = new GridData(768);
		griddata.horizontalSpan = 2;
		urlCombo.setLayoutData(griddata);
		urlCombo.addModifyListener(new ModifyListener() {
			public void modifyText(ModifyEvent modifyevent) {
				dbConnection.setUrl(urlCombo.getText().trim());
				checkInput();
			}
		});
	}

	private void createDbTypeField(Composite composite) {
		Label label = new Label(composite, 0);
		GridData griddata = new GridData();
		griddata.horizontalSpan = 1;
		griddata.grabExcessHorizontalSpace = false;
		label.setText(Messages.getString("ManageConnectionDialog.databasetype")); //$NON-NLS-1$
		label.setLayoutData(griddata);
		dbTypeCombo = new Combo(composite, 67592);
		GridData griddata1 = new GridData(768);
		griddata1.horizontalSpan = 2;
		dbTypeCombo.setLayoutData(griddata1);

		fillHerUp(dbTypeCombo, helper.getDialectNames());
		dbTypeCombo.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent selectionevent) {
				dbConnection.setType(dbTypeCombo.getText().trim());
				fillHerUp(driverClassCombo, helper
						.getDriverClasses(dbConnection.getType()));

				checkInput();
			}
		});
	}

	private void createDriverClassField(Composite composite) {
		Label label = new Label(composite, 0);
		GridData griddata = new GridData();
		griddata.horizontalSpan = 1;
		label.setText(Messages.getString("ManageConnectionDialog.driverclassname")); //$NON-NLS-1$
		driverClassCombo = new Combo(composite, 67584);
		driverClassCombo.setTextLimit(100);
		GridData griddata1 = new GridData(768);
		griddata1.horizontalSpan = 2;
		driverClassCombo.setLayoutData(griddata1);
		driverClassCombo.addModifyListener(new ModifyListener() {
			public void modifyText(ModifyEvent modifyevent) {
				dbConnection.setDriverClassName(driverClassCombo.getText()
						.trim());

				fillHerUp(urlCombo, helper.getConnectionURLS(dbConnection
						.getType()));

				checkInput();
			}
		});
	}

	private void createJdbcDriverField(Composite composite) {
		Label label = new Label(composite, 0);
		label.setText(Messages.getString("ManageConnectionDialog.driverclassurl")); //$NON-NLS-1$
		GridData griddata = new GridData();
		griddata.horizontalSpan = 1;
		label.setLayoutData(griddata);
		driverPathCombo = new Combo(composite, 67584);
		driverPathCombo.setTextLimit(200);
		GridData griddata1 = new GridData(768);
		griddata1.horizontalSpan = 1;
		griddata1.widthHint = convertWidthInCharsToPixels(30);
		driverPathCombo.setLayoutData(griddata1);
		driverPathCombo.addModifyListener(new ModifyListener() {
			public void modifyText(ModifyEvent modifyevent) {
				dbConnection.setDriverPath(driverPathCombo.getText().trim());
				checkInput();
			}
		});

		Button button = new Button(composite, 8);
		button.setLayoutData(new GridData(4, 16777216, false, false));
		button.setText(Messages.getString("ManageConnectionDialog.browsing")); //$NON-NLS-1$
		setButtonLayoutData(button);
		button.addSelectionListener(new SelectionAdapter() {

			public void widgetSelected(SelectionEvent selectionevent) {
				FileDialog filedialog = SaturnDialogUtil.createFileDialog(
						Messages.getString("ManageConnectionDialog.choosedirverpackage"), //$NON-NLS-1$
						new String[] { "*.jar;*.zip" }); //$NON-NLS-1$

				if (filedialog.open() != null) {
					String files[] = filedialog.getFileNames();
					String path = filedialog.getFilterPath();

					StringBuffer pathBuff = new StringBuffer();
					for (int i = 0; i < files.length; i++) {
						pathBuff.append(path).append(
								File.separatorChar + files[i]);

						if (i < files.length - 1) {
							pathBuff.append(";"); //$NON-NLS-1$
						}
					}

					driverPathCombo.setText(pathBuff.toString());
					dbConnection.setDriverPath(pathBuff.toString());
				}
			}
		});
	}

	private void createPwdField(Composite composite) {
		Label label = new Label(composite, 0);
		GridData griddata = new GridData();
		griddata.horizontalSpan = 1;
		label.setText(Messages.getString("ManageConnectionDialog.databasepassword")); //$NON-NLS-1$
		label.setLayoutData(griddata);
		pwdTxt = new Text(composite, 2048);
		pwdTxt.setTextLimit(50);
		pwdTxt.setEchoChar('*');
		GridData griddata1 = new GridData(768);
		griddata1.horizontalSpan = 2;
		pwdTxt.setLayoutData(griddata1);
		pwdTxt.addModifyListener(new ModifyListener() {
			public void modifyText(ModifyEvent modifyevent) {
				dbConnection.setPassword(pwdTxt.getText().trim());
				checkInput();
			}
		});
	}

	private void createUsrField(Composite composite) {
		Label label = new Label(composite, 0);
		label.setText(Messages.getString("ManageConnectionDialog.databaseuser")); //$NON-NLS-1$
		GridData griddata = new GridData();
		griddata.horizontalSpan = 1;
		label.setLayoutData(griddata);
		usridTxt = new Text(composite, 2048);
		usridTxt.setTextLimit(50);
		GridData griddata1 = new GridData(768);
		griddata1.horizontalSpan = 2;
		usridTxt.setLayoutData(griddata1);
		usridTxt.addModifyListener(new ModifyListener() {
			public void modifyText(ModifyEvent modifyevent) {
				dbConnection.setUsername(usridTxt.getText().trim());
				checkInput();
			}
		});
	}

	private void createNameField(Composite composite) {
		Label label = new Label(composite, 0);
		label.setText(Messages.getString("ManageConnectionDialog.linkname")); //$NON-NLS-1$
		GridData griddata = new GridData();
		griddata.horizontalSpan = 1;
		label.setLayoutData(griddata);
		nameTxt = new Text(composite, 2048);
		nameTxt.setTextLimit(50);
		GridData griddata1 = new GridData(768);
		griddata1.horizontalSpan = 2;
		nameTxt.setLayoutData(griddata1);
		nameTxt.setFocus();
		nameTxt.setText(getDefaultInitName());
		nameTxt.addModifyListener(new ModifyListener() {
			public void modifyText(ModifyEvent modifyevent) {
				dbConnection.setName(nameTxt.getText().trim());
				checkInput();
			}
		});
	}

	private boolean checkConnectionExitsIgnoreCase(String s) {
		Collection<DBConnection> dbConnections = DBConnectionProvider
				.getInstance().getAllDBConnections();

		if (dbConnections != null) {
			for (DBConnection connection : dbConnections) {
				if (connection.getName().equalsIgnoreCase(s)) {
					return true;
				}
			}
		}
		return false;
	}

	private String getDefaultInitName() {
		String s = "connection1"; //$NON-NLS-1$

		for (int i = 1; checkConnectionExitsIgnoreCase(s); i++) { //$NON-NLS-1$
			s = "connection" + i; //$NON-NLS-1$
		}

		return s;
	}

	private boolean checkInput() {
		if (isModify && isInit) {
			return false;
		}
		setMessage(null);
		setError(null);
		String name = nameTxt.getText().trim();
		if (SaturnValidation.isEmpty(name)) {
			setError(Messages.getString("ManageConnectionDialog.linkpropertylimit"));  //$NON-NLS-1$
			return false;
		}
		if (SaturnValidation.isBadWord(name)) {
			setError(Messages.getString("ManageConnectionDialog.writelimit"));  //$NON-NLS-1$
			return false;
		}
		if (!this.isModify && checkConnectionExitsIgnoreCase(name)) {
			setError(Messages.getString("ManageConnectionDialog.linknameduplicated")); //$NON-NLS-1$
			return false;
		}
		String type = dbTypeCombo.getText().trim();
		if (SaturnValidation.isEmpty(type)) {
			setError(Messages.getString("ManageConnectionDialog.databaseproperyempty")); //$NON-NLS-1$
			return false;
		}
		String driverClass = driverClassCombo.getText().trim();
		if (SaturnValidation.isEmpty(driverClass)) {
			setError(Messages.getString("ManageConnectionDialog.driverclassnamepropertyempty")); //$NON-NLS-1$
			return false;
		}
		String url = urlCombo.getText().trim();
		if (SaturnValidation.isEmpty(url)) {
			setError(Messages.getString("ManageConnectionDialog.urlpropertyempty"));  //$NON-NLS-1$
			return false;
		}
		String user = usridTxt.getText().trim();
		if (SaturnValidation.isEmpty(user)) {
			setError(Messages.getString("ManageConnectionDialog.databaseuserpropertyempty")); //$NON-NLS-1$
			return false;
		}

		if (SaturnValidation.isBadWord(user)) {
			setError(Messages.getString("ManageConnectionDialog.databaseuserpropertyillegal")); //$NON-NLS-1$
			return false;
		}

		String driverPath = driverPathCombo.getText().trim();
		if (SaturnValidation.isEmpty(driverPath)) {
			setError(Messages.getString("ManageConnectionDialog.driverurlpropertyempty"));  //$NON-NLS-1$
			return false;
		}

		setMessage(Messages.getString("ManageConnectionDialog.clicktestlink")); //$NON-NLS-1$
		testConBtn.setEnabled(true);
		return true;
	}

	private void refresh() {
		nameTxt.setText(dbConnection.getName());
		dbTypeCombo.setText(dbConnection.getType());
		usridTxt.setText(dbConnection.getUsername());
		pwdTxt.setText(dbConnection.getPassword());
		urlCombo.setText(dbConnection.getUrl());
		driverPathCombo.setText(dbConnection.getDriverPath());
		driverClassCombo.setText(dbConnection.getDriverClassName());
	}

	protected void cancelPressed() {
		super.cancelPressed();
	}

	protected void okPressed() {
		if (this.checkInput() && this.canOk) {
			saveWidgetValues();
			validateConWhenOK();
		}
	}

	private void validateConWhenOK() {
		try {
			if (isModify) {
				String newName = this.oldName;
				if (!this.oldName.equals(dbConnection.getName())) {
					newName = dbConnection.getName();
					dbConnection.setName(this.oldName);
				}
				
				DBConnectionProvider.getInstance().removeDBConnection(
						dbConnection);
				DBConnectView.getInstance().removeDbConnection(dbConnection);
				
				dbConnection.setName(newName);
			}

			DBConnectionProvider.getInstance().addConnection(dbConnection);
			DBConnectView.getInstance().addDbConnection(dbConnection);

			super.okPressed();
		} catch (Exception e) {
			//SaturnDialogUtil.openError(this.getShell(), Messages
					//.getString("ManageConnectionDialog.44")); //$NON-NLS-1$
			e.printStackTrace();
		}
	}

	private void setError(String s) {
		super.setErrorMessage(s);
		refreshBtnState(false);
	}

	protected void restoreWidgetValues() {
		SaturnDialogSettings dialogSettings = SaturnDialogUtil
				.getSaturnDialogSettings(Activator.getDefault());

		String[] urls = dialogSettings.getHistory(STORE_SECTION_NAME,
				STORE_URL_KEY);
		String url = urlCombo.getText();
		if (urls != null && urls.length > 0) {
			urlCombo.setItems(urls);
		}
		urlCombo.setText(url);

		String[] driverPaths = dialogSettings.getHistory(STORE_SECTION_NAME,
				STORE_DRIVERPATH_KEY);
		
		String driverPath = driverPathCombo.getText();
		if (driverPaths != null) {
			driverPathCombo.setItems(driverPaths);
		}
		driverPathCombo.setText(driverPath);
	}

	protected void saveWidgetValues() {
		SaturnDialogSettings dialogSettings = SaturnDialogUtil
				.getSaturnDialogSettings(Activator.getDefault());

		dialogSettings.addHistory(STORE_SECTION_NAME, STORE_URL_KEY, urlCombo
				.getText().trim());
		dialogSettings.addHistory(STORE_SECTION_NAME, STORE_DRIVERPATH_KEY,
				driverPathCombo.getText().trim());
	}

	protected void configureShell(Shell newShell) {
		super.configureShell(newShell);
		newShell.setImage(Activator.getImage(Images.DATABASE_NODE11)); //$NON-NLS-1$
	}

	private void fillHerUp(Combo combo, Collection<String> newContent) {
		String original = combo.getText();
		combo.removeAll();

		if (newContent != null) {
			for (String name : newContent) {
				combo.add(name);
			}
		}

		combo.setText(original);
	}

	private void fillHerUp(Combo combo, String newContent) {
		String original = combo.getText();
		combo.removeAll();

		combo.add(newContent);

		combo.setText(original);
	}

}
